﻿using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using MemHack.Mem;

namespace MemHack.Util
{
	public static class MemUtil
	{
		/// <summary>
		/// 将基本类型转为byte数组,非基本类型返回null
		/// </summary>
		/// <typeparam name="T">基本类型</typeparam>
		/// <param name="data">数据</param>
		/// <returns>byte数组</returns>
		public static byte[] ConvertBeseTypeToBytes<T>(T data)
		{
			byte[] bytes = null;
			do
			{
				if (typeof(T) == typeof(byte))
				{
					object val = Convert.ChangeType(data, typeof(byte));
					bytes = new byte[] {(byte)val};
					break;
				}

				if (typeof(T) == typeof(int))
				{
					object val = Convert.ChangeType(data, typeof(int));
					bytes = BitConverter.GetBytes((int)val);
					break;
				}

				if (typeof(T) == typeof(short))
				{
					object val = Convert.ChangeType(data, typeof(short));
					bytes = BitConverter.GetBytes((short)val);
					break;
				}

				if (typeof(T) == typeof(float))
				{
					object val = Convert.ChangeType(data, typeof(float));
					bytes = BitConverter.GetBytes((float)val);
					break;
				}

				if (typeof(T) == typeof(double))
				{
					object val = Convert.ChangeType(data, typeof(double));
					bytes = BitConverter.GetBytes((double)val);
					break;
				}

				if (typeof(T) == typeof(long))
				{
					object val = Convert.ChangeType(data, typeof(long));
					bytes = BitConverter.GetBytes((long) val);
					break;
				}

				if (typeof(T) == typeof(bool))
				{
					object val = Convert.ChangeType(data, typeof(bool));
					bytes = BitConverter.GetBytes((bool) val);
					break;
				}

				if (typeof(T) == typeof(char))
				{
					object val = Convert.ChangeType(data, typeof(char));
					bytes = BitConverter.GetBytes((char)val);
					break;
				}

				if (typeof(T) == typeof(ushort))
				{
					object val = Convert.ChangeType(data, typeof(ushort));
					bytes = BitConverter.GetBytes((ushort)val);
					break;
				}

				if (typeof(T) == typeof(uint))
				{
					object val = Convert.ChangeType(data, typeof(uint));
					bytes = BitConverter.GetBytes((uint)val);
					break;
				}

				if (typeof(T) == typeof(ulong))
				{
					object val = Convert.ChangeType(data, typeof(ulong));
					bytes = BitConverter.GetBytes((ulong)val);
					break;
				}

			} while (false);

			if (bytes == null)
			{
				throw new ArgumentException($"类型传入错误,非基本类型转换错误:[{data.GetType()}]");
			}
			return bytes;
		}

		/// <summary>
		/// 将字节数组转换为基本类型
		/// </summary>
		/// <typeparam name="T">基本类型</typeparam>
		/// <param name="bytes">字节数组</param>
		/// <returns>转换后的基本类型</returns>
		public static T ConvertBytesToBaseType<T>(byte[] bytes)
		{
			if (typeof(T) == typeof(byte))
			{
				if (bytes.Length != 1)
				{
					throw new ArgumentException("数组长度不为1,无法转换为byte类型");
				}

				return (T)(object)bytes[0];
			}

			if (typeof(T) == typeof(int))
			{
				return (T) Convert.ChangeType(BitConverter.ToInt32(bytes, 0), typeof(int));
			}

			if (typeof(T) == typeof(short))
			{
				return (T)Convert.ChangeType(BitConverter.ToInt16(bytes, 0), typeof(short));
			}

			if (typeof(T) == typeof(float))
			{
				return (T)Convert.ChangeType(BitConverter.ToSingle(bytes, 0), typeof(float));
			}

			if (typeof(T) == typeof(double))
			{
				return (T)Convert.ChangeType(BitConverter.ToDouble(bytes, 0), typeof(double));
			}

			if (typeof(T) == typeof(long))
			{
				return (T)Convert.ChangeType(BitConverter.ToInt64(bytes, 0), typeof(long));
			}

			if (typeof(T) == typeof(bool))
			{
				return (T)Convert.ChangeType(BitConverter.ToBoolean(bytes, 0), typeof(bool));
			}

			if (typeof(T) == typeof(char))
			{
				return (T)Convert.ChangeType(BitConverter.ToChar(bytes, 0), typeof(char));
			}

			if (typeof(T) == typeof(ushort))
			{
				return (T)Convert.ChangeType(BitConverter.ToUInt16(bytes, 0), typeof(ushort));
			}

			if (typeof(T) == typeof(uint))
			{
				return (T)Convert.ChangeType(BitConverter.ToUInt32(bytes, 0), typeof(uint));
			}

			if (typeof(T) == typeof(ulong))
			{
				return (T)Convert.ChangeType(BitConverter.ToUInt64(bytes, 0), typeof(ulong));
			}
			throw new ArgumentException($"类型传入错误,非基本类型转换错误:[{typeof(T)}]");
		}

		/// <summary>
		/// 获取指定基本类型占用的字节数
		/// </summary>
		/// <typeparam name="T">基本类型的泛型</typeparam>
		/// <returns>该类型占用的字节数</returns>
		public static int SizeOfBaseType<T>() where T : unmanaged
		{
			return Marshal.SizeOf<T>();
		}

		/// <summary>
		/// 判断内存模式是否可读
		/// </summary>
		/// <param name="protectMode">内存页保护模式</param>
		/// <returns>是否可读</returns>
		public static bool MemCanRead(uint protectMode)
		{
			uint canReadMode = (uint) (PAGE_PROTECT.PAGE_READWRITE | PAGE_PROTECT.PAGE_EXECUTE_READ |
			                           PAGE_PROTECT.PAGE_EXECUTE_READWRITE | PAGE_PROTECT.PAGE_READONLY);
			return (protectMode & canReadMode) != 0;
		}

		/// <summary>
		/// 判断内存模式是否可写
		/// </summary>
		/// <param name="protectMode">内存页保护模式</param>
		/// <returns>是否可写</returns>
		public static bool MemCanWrite(uint protectMode)
		{
			uint canWriteMode = (uint)(PAGE_PROTECT.PAGE_WRITECOPY | PAGE_PROTECT.PAGE_READWRITE |
			                           PAGE_PROTECT.PAGE_EXECUTE_WRITECOPY | PAGE_PROTECT.PAGE_EXECUTE_READWRITE);
			return (protectMode & canWriteMode) != 0;
		}

		/// <summary>
		/// 内存页是否只读
		/// </summary>
		/// <param name="protectMode">保护模式</param>
		/// <returns>内存页是否只读</returns>
		public static bool MemIsReadOnly(uint protectMode)
		{
			return (protectMode & (uint) PAGE_PROTECT.PAGE_READONLY) != 0;
		}

		/// <summary>
		/// 内存页是否可读写
		/// </summary>
		/// <param name="protectMode"保护模式></param>
		/// <returns>内存页是否可读写</returns>
		public static bool MemCanReadWrite(uint protectMode)
		{
			return  (protectMode & (uint)PAGE_PROTECT.PAGE_READWRITE) == (uint)PAGE_PROTECT.PAGE_READWRITE ||
			       (protectMode & (uint)PAGE_PROTECT.PAGE_EXECUTE_READWRITE) == (uint)PAGE_PROTECT.PAGE_EXECUTE_READWRITE;
		}

		/// <summary>
		/// 将字节数组转为十六进制字符串
		/// </summary>
		/// <param name="bytes"></param>
		/// <returns>十六进制字符串</returns>
		public static string ToHexStr(this byte[] bytes)
		{
			StringBuilder sb = new StringBuilder();
			foreach (byte b in bytes)
			{
				sb.Append(b.ToString("X2")).Append(" ");
			}
			return sb.ToString().Trim();
		}

		/// <summary>
		/// 将以空格分割的十六进制字节字符串转为byte数组
		/// </summary>
		/// <param name="byteStr">"AB CD 12 0D"</param>
		/// <returns>byte数组</returns>
		public static byte[] HexBytesStrToArr(string byteStr)
		{
			string[] bytesArr = byteStr.Trim().Split(' ')
				.Where(s => !string.IsNullOrWhiteSpace(s))
				.ToArray();
			byte[] bytes = new byte[bytesArr.Length];
			for (var i = 0; i < bytesArr.Length; i++)
			{
				try
				{
					bytes[i] = Convert.ToByte(bytesArr[i], 16);
				}
				catch (Exception)
				{
					throw new Exception($"{bytesArr[i]} 不是一个十六进制字节字符串");
				}
			}
			return bytes;
		}
	}
}
